<?php

namespace System\library\config;

use System\library\utility\Validate;

/**
 * <b>Class</b> :        Config<br>
 * <b>Fonction</b> :     Permet la gestion des constantes et variables de configuration
 * <br>
 * @version              1.0
 * @author               Steuf
 * @license              Licence publique générale GNU http://www.gnu.org/licenses/gpl.html
 * @copyright            Copyright 2011 - MidichloriansPHP and contributors
 * @package              System
 * @subpackage           library\config
 */
class Config {

    /**
     * L'attribut qui permet de stocker les constantes sous forme d'array
     *
     * @access private
     * @static
     * @var array
     */
    private static $_cons = array();
    /**
     * L'attribut qui permet de stocker les variables sous forme d'array
     *
     * @access private
     * @static
     * @var array
     */
    private static $_var = array();

    /**
     * Permet de définir une constante de configuration
     *
     * @access public
     * @static
     * @param string $name nom de la constante à définir
     * @param mixed $value valeur de la constante à définir
     * @return void
     *
     * @see \MidichloriansPHP\utility\Validate
     */
    public static function setCons($name, $value) {
        if (empty($name) || !is_string($name))
            throw new \Exception('Name of constant must be as non empty string');
        if (!Validate::isVariableName($name))
            throw new \Exception('Name must be a valid variable name');
        if (array_key_exists($name, self::$_cons))
            throw new \Exception('Constant ' . $name . ' already defined');
        if (is_string($value))
            self::$_cons[$name] = preg_replace('#\[([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\]#e', "System\library\config\Config::getCons('$1')", $value);
        else
            self::$_cons[$name] = $value;
    }

    /**
     * Permet de définir une variable de configuration
     *
     * @access public
     * @static
     * @param string $name nom de la variable à définir
     * @param mixed $value valeur de la variable à définir
     * @return void
     *
     * @see \MidichloriansPHP\utility\Validate
     */
    public static function setVar($name, $value) {
        if (empty($name) || !is_string($name))
            throw new \Exception('Name of variable must be as non empty string');
        if (!Validate::isVariableName($name))
            throw new \Exception('Name must be a valid variable name');
        if (!is_string($name))
            throw new \Exception('The name of the variable must be a string');
        if (is_string($value))
            self::$_var[$name] = preg_replace('#\[([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\]#e', "System\library\config\Config::getCons('$1')", $value);
        else
            self::$_var[$name] = $value;
    }

    /**
     * Permet d'obtenir la valeur d'une constante, engendre une exception si celle-ci n'existe pas
     * Il peut avoir plusieurs paramètres pour obtenir un élément de tableau
     * @example For array(
     *      'key' => array(
     *          'two' => 'Blabala'
     *      )
     * Config::getCons('key') ==> return array('two' => 'Blabala')
     * Config::getCons('key','two') ==> return String 'Blabala'
     *
     * @access public
     * @static
     * @param string $name nom de la constante
     * @return mixed La valeur de la constante désirée
     */
    public static function getCons($name) {
        if (func_num_args() == 0)
            throw new \Exception('For getting a constant you must set at least one parameter');

        $args = func_get_args();
        foreach ($args as $k => &$value) {
            if (!is_string($value) && !is_int($value))
                throw new \Exception('The name of constant ' . $k . ' must be a string or an integer');
            if (!array_key_exists($value, self::$_cons))
                throw new \Exception('Constant ' . $value . ' don\'t exist');
            $tab = self::$_cons[$value];
        }
        if (is_string($tab))
            return preg_replace('#{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)}#e', "System\library\config\Config::getVar('$1')", $tab);
        else
            return $tab;
    }

    /**
     * Permet se savoir si une constante est définit
     *
     * @access public
     * @static
     * @param string $name nom de la constante
     * @return bool true si la constante est définit, false, si non
     */
    public static function isDefinedCons($name) {
        if (!is_string($name))
            throw new \Exception('The name of the constant must be a string');
        return array_key_exists($name, self::$_cons);
    }

    /**
     * Permet d'obtenir la valeur d'une variable, engendre une exception si celle-ci n'existe pas
     * Il peut avoir plusieurs paramètres pour obtenir un élément de tableau
     * @example For array(
     *      'key' => array(
     *          'two' => 'Blabala'
     *      )
     * Config::getVar('key') ==> return array('two' => 'Blabala')
     * Config::getVar('key','two') ==> return String 'Blabala'
     *
     * @access public
     * @static
     * @param string $name nom de la variable
     * @return mixed La valeur de la variable désirée
     */
    public static function getVar($name) {
        if (func_num_args() == 0)
            throw new \Exception('For getting a var you must set at least one parameter');

        $args = func_get_args();
        $tab = self::$_var;

        foreach ($args as $k => &$value) {
            if (!is_string($value) && !is_int($value))
                throw new \Exception('The name of constant ' . $k . ' must be a string or an integer');
            if (!array_key_exists($value, $tab))
                throw new \Exception('Variable ' . $value . ' don\'t exist');
            $tab = $tab[$value];
        }
        if (is_string($tab))
            return preg_replace('#{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)}#e', "System\library\Config::getVar('$1')", $tab);
        else
            return $tab;
    }

    /**
     * Permet d'obtenir toutes les constantes contenue dans le tableaux self::$_cons indéxé par le nom des constantes
     *
     * @access public
     * @static
     * @param void
     * @return array Tableau contenant toutes les constantes définit au préalable
     */
    public static function getAllCons() {
        $cons = array();
        $consKeys = array_keys(self::$_cons);
        foreach ($consKeys as &$key)
            $cons[$key] = self::getCons($key);
        return $cons;
    }

    /**
     * Permet d'obtenir toutes les variables contenue dans le tableaux self::$_var indéxé par le nom des variables
     *
     * @access public
     * @static
     * @param void
     * @return array Tableau contenant toutes les variables définit au préalable
     */
    public static function getAllVar() {
        $vars = array();
        $varsKeys = array_keys(self::$_var);
        foreach ($varsKeys as &$key)
            $vars[$key] = self::getVar($key);
        return $vars;
    }

    /**
     * Permet de charger une configuration (définir les varibales et constantes) depuis un fichier ini
     * 
     * @access public
     * @static
     * @param string $file le fichier ini à charger
     * return void
     */
    public static function loadIniFile($file) {
        if (!file_exists($file))
            throw new \Exception('File "' . $file . "' don\'t exists");
        $datas = parse_ini_file($file, true);
        if (!$datas)
            throw new \Exception('File "' . $file . "' is not a valid ini file");
        self::_load($datas);
    }

    /**
     * Permet de charger une configuration (définir les varibales et constantes) depuis un ini string
     *
     * @access public
     * @static
     * @param string $string ini string
     * return void
     */
    public static function loadIniString($string) {
        $datas = parse_ini_string($string, true);
        if (!$datas)
            throw new \Exception('Parameter is not a valid ini string');
        self::_load($datas);
    }

    /**
     * Permet de charger une configuration (définir les varibales et constantes) depuis un array (celui qui sera créer après un parse_ini d'un fichier ou string ini
     * 
     * @access private
     * @static
     * @param array $array le tableau à charger
     * return void
     */
    private static function _load($array) {
        foreach ($array as $type => &$values) {
            if ($type == 'Constants' && count($values) > 0) {
                foreach ($values as $key => &$value)
                    self::setCons($key, $value);
            } elseif ($type == 'Variables' && count($values) > 0) {
                foreach ($values as $key => &$value)
                    self::setVar($key, $value);
            }
        }
    }

}

?>
